<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <title>DictionaryService and DictionaryHub Pattern | HiAPI-C# 2025 </title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta name="title" content="DictionaryService and DictionaryHub Pattern | HiAPI-C# 2025 ">
      
      
      <link rel="icon" href="../../../../img/HiAPI.favicon.ico">
      <link rel="stylesheet" href="../../../../public/docfx.min.css">
      <link rel="stylesheet" href="../../../../public/main.css">
      <meta name="docfx:navrel" content="../../../../toc.html">
      <meta name="docfx:tocrel" content="../../toc.html">
      
      <meta name="docfx:rel" content="../../../../">
      
      
      
      <meta name="loc:inThisArticle" content="In this article">
      <meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
      <meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
      <meta name="loc:tocFilter" content="Filter by title">
      <meta name="loc:nextArticle" content="Next">
      <meta name="loc:prevArticle" content="Previous">
      <meta name="loc:themeLight" content="Light">
      <meta name="loc:themeDark" content="Dark">
      <meta name="loc:themeAuto" content="Auto">
      <meta name="loc:changeTheme" content="Change theme">
      <meta name="loc:copy" content="Copy">
      <meta name="loc:downloadPdf" content="Download PDF">

      <script type="module" src="./../../../../public/docfx.min.js"></script>

      <script>
        const theme = localStorage.getItem('theme') || 'auto'
        document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
      </script>

  </head>

  <body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
    <header class="bg-body border-bottom">
      <nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
        <div class="container-xxl flex-nowrap">
          <a class="navbar-brand" href="../../../../index.html">
            <img id="logo" class="svg" src="../../../../img/HiAPI.logo.png" alt="">
            
          </a>
          <button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
            <i class="bi bi-three-dots"></i>
          </button>
          <div class="collapse navbar-collapse" id="navpanel">
            <div id="navbar">
              <form class="search" role="search" id="search">
                <i class="bi bi-search"></i>
                <input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
              </form>
            </div>
          </div>
        </div>
      </nav>
    </header>

    <main class="container-xxl">
      <div class="toc-offcanvas">
        <div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
          <div class="offcanvas-header">
            <h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
            <button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
          </div>
          <div class="offcanvas-body">
            <nav class="toc" id="toc"></nav>
          </div>
        </div>
      </div>

      <div class="content">
        <div class="actionbar">
          <button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
            <i class="bi bi-list"></i>
          </button>

          <nav id="breadcrumb"></nav>
        </div>

        <article data-uid="">
          <h1 id="dictionaryservice-and-dictionaryhub-pattern">DictionaryService and DictionaryHub Pattern</h1>

<h2 id="overview">Overview</h2>
<p>A connection-scoped indexing pattern for referencing backend objects across hierarchical SignalR hub connections.</p>
<h2 id="core-components">Core Components</h2>
<p><code>DictionaryService</code>: Manages connection-scoped index dictionaries</p>
<ul>
<li>First layer key: Hub connectionId (auto-generated by SignalR)</li>
<li>Second layer key: LocalId (resource name)</li>
<li>Value: References to backend objects (functions, getters/setters)</li>
</ul>
<p><code>DictionaryHub</code>: Base hub that auto-cleans index entries on disconnect</p>
<h2 id="architecture">Architecture</h2>
<pre><code>Root-Hub
└── Child-Hub - has parent's connectionId
    └── Grandchild-Hub - has parent's connectionId
</code></pre>
<p>Each hub gets a unique system-generated hub-connectionId. Child hubs receive parent's connectionId to access parent data.</p>
<h2 id="key-patterns">Key Patterns</h2>
<ol>
<li><strong>Parent ConnectionId Passing</strong>: Child hubs copy parent's function references via connectionId</li>
<li><strong>Frontend ConnectionId Chain</strong>: Components pass connectionId down the hierarchy</li>
<li><strong>Wrapper Function Pattern</strong>: Child hubs should create wrapper functions that dynamically retrieve and invoke parent functions at runtime, rather than directly copying references. This ensures type safety through runtime checking and supports dynamic function updates from the parent.</li>
</ol>
<h2 id="benefits">Benefits</h2>
<ul>
<li><strong>Isolation</strong>: Each component has its own connection/index space</li>
<li><strong>Nesting Support</strong>: Same components can be nested without conflicts</li>
<li><strong>Auto-cleanup</strong>: Index entries cleaned on disconnect</li>
<li><strong>Data Inheritance</strong>: Access parent's backend objects via connectionId chain</li>
</ul>
<h2 id="best-practices">Best Practices</h2>
<ul>
<li>Apply or inherit from DictionaryHub for auto-cleanup</li>
<li>Use meaningful key names (e.g., &ldquo;transformer-getter&rdquo;)</li>
<li>Always setup dictionary functions unconditionally during initialization - put condition checks inside the functions, not around the setup. This ensures child panels can access functions even when parent objects temporarily don't meet the conditions.</li>
</ul>
<h2 id="common-pitfalls">Common Pitfalls</h2>
<ul>
<li>Don't use child's connectionId to index parent's data</li>
</ul>

</article>

        <div class="contribution d-print-none">
        </div>

        <div class="next-article d-print-none border-top" id="nextArticle"></div>

      </div>

      <div class="affix">
        <nav id="affix"></nav>
      </div>
    </main>

    <div class="container-xxl search-results" id="search-results"></div>

    <footer class="border-top text-secondary">
      <div class="container-xxl">
        <div class="flex-fill">
          <span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
        </div>
      </div>
    </footer>
  </body>
</html>
